package com.photovoltaic.neo4j.service;

import lombok.RequiredArgsConstructor;
import org.neo4j.driver.*;
import org.neo4j.driver.Record;
import org.neo4j.driver.types.Node;
import org.neo4j.driver.types.Relationship;
import org.springframework.stereotype.Service;

import java.util.*;

import static org.neo4j.driver.Values.parameters;

/**
 * 产品相关服务类
 */
@Service
@RequiredArgsConstructor
public class ProductService {
    private final Driver neo4jDriver;

    /**
     * 搜索产品
     * @param keyword 关键词
     * @return 产品列表
     */
    public List<Map<String, Object>> searchProducts(String keyword) {
        try (Session session = neo4jDriver.session()) {
            return session.readTransaction(tx -> {
                String query;
                
                // 如果关键词为空，则返回所有产品（限制数量）
                if (keyword == null || keyword.trim().isEmpty()) {
                    query = "MATCH (p:Product) " +
                            "RETURN id(p) as id, p.name as name, " +
                            "p.description as description, " +
                            "labels(p) as labels " +
                            "ORDER BY p.name " +
                            "LIMIT 10";
                    return executeProductSearch(tx, query, null);
                } else {
                    query = "MATCH (p:Product) WHERE toLower(p.name) CONTAINS toLower($keyword) " +
                            "RETURN id(p) as id, p.name as name, " +
                            "p.description as description, " +
                            "labels(p) as labels " +
                            "LIMIT 10";
                    return executeProductSearch(tx, query, keyword);
                }
            });
        }
    }
    
    /**
     * 执行产品搜索
     */
    private List<Map<String, Object>> executeProductSearch(Transaction tx, String query, String keyword) {
        Result result;
        if (keyword == null) {
            result = tx.run(query);
        } else {
            result = tx.run(query, parameters("keyword", keyword));
        }
        
        List<Map<String, Object>> products = new ArrayList<>();
        while (result.hasNext()) {
            Record record = result.next();
            Map<String, Object> product = new HashMap<>();
            product.put("id", record.get("id").toString());
            product.put("name", record.get("name").asString());
            
            // 处理可能为空的字段
            Value descValue = record.get("description");
            if (!descValue.isNull()) {
                product.put("description", descValue.asString());
            } else {
                product.put("description", "");
            }
            
            // 获取节点标签
            List<String> labels = record.get("labels").asList(Value::asString);
            product.put("type", labels.contains("Product") ? "Product" : labels.get(0));
            
            products.add(product);
        }
        return products;
    }
    
    /**
     * 获取产品上下游关系
     * @param productName 产品名称
     * @param depth 查询深度
     * @param direction 查询方向 (upstream/downstream/both)
     * @return 产品上下游关系数据
     */
    public Map<String, Object> getProductChain(String productName, Integer depth, String direction) {
        try (Session session = neo4jDriver.session()) {
            return session.readTransaction(tx -> {
                // 如果产品名称为空，则返回默认数据集
                if (productName == null || productName.trim().isEmpty()) {
                    // 查询几个主要产品的关系
                    String defaultQuery = "MATCH (p:Product) " +
                                         "WITH p LIMIT 5 " +
                                         "OPTIONAL MATCH (p)-[r:UPSTREAM_OF]-(related) " +
                                         "RETURN collect(distinct p) as nodes, collect(distinct r) as rels";
                    
                    return processDefaultProductChain(tx, defaultQuery);
                }
                
                // 以下是原来的代码，处理有产品名称的情况
                // 构建查询语句，根据方向选择不同的关系模式
                StringBuilder queryBuilder = new StringBuilder();
                queryBuilder.append("MATCH (p:Product {name: $productName}) ");
                
                // 根据方向构建不同的查询路径
                if ("upstream".equals(direction)) {
                    // 上游：查找是该产品上游的产品/材料
                    // A UPSTREAM_OF B 表示A是B的上游
                    queryBuilder.append("OPTIONAL MATCH path = (material)-[:UPSTREAM_OF*1..").append(depth).append("]->(p) ");
                } else if ("downstream".equals(direction)) {
                    // 下游：查找该产品是其上游的产品/材料
                    // A UPSTREAM_OF B 表示A是B的上游，所以p UPSTREAM_OF product表示p是product的上游
                    queryBuilder.append("OPTIONAL MATCH path = (p)-[:UPSTREAM_OF*1..").append(depth).append("]->(product) ");
                } else {
                    // 默认双向：同时查找上下游
                    queryBuilder.append("OPTIONAL MATCH path1 = (material)-[:UPSTREAM_OF*1..").append(depth).append("]->(p) ");
                    queryBuilder.append("OPTIONAL MATCH path2 = (p)-[:UPSTREAM_OF*1..").append(depth).append("]->(product) ");
                    queryBuilder.append("WITH p, path1, path2 ");
                    queryBuilder.append("WITH p, [path1, path2] AS paths ");
                    queryBuilder.append("UNWIND paths AS path ");
                }
                
                // 提取节点和关系
                if ("both".equals(direction)) {
                    queryBuilder.append("WITH p, path WHERE path IS NOT NULL ");
                } else {
                    queryBuilder.append("WITH p, path ");
                }
                
                queryBuilder.append("UNWIND nodes(path) AS node ");
                queryBuilder.append("UNWIND relationships(path) AS rel ");
                queryBuilder.append("WITH COLLECT(DISTINCT node) AS nodes, COLLECT(DISTINCT rel) AS rels, p ");
                queryBuilder.append("RETURN nodes + p AS allNodes, rels AS allRelationships");
                
                return processProductChain(tx, queryBuilder.toString(), productName);
            });
        }
    }
    
    /**
     * 处理默认产品链查询结果
     */
    private Map<String, Object> processDefaultProductChain(Transaction tx, String query) {
        Result defaultResult = tx.run(query);
        if (defaultResult.hasNext()) {
            Record record = defaultResult.next();
            
            List<Node> nodeList = record.get("nodes").asList(Value::asNode);
            List<Relationship> relList = record.get("rels").asList(Value::asRelationship);
            
            List<Map<String, Object>> nodes = new ArrayList<>();
            List<Map<String, Object>> relationships = new ArrayList<>();
            
            // 处理节点
            for (Node node : nodeList) {
                Map<String, Object> nodeMap = new HashMap<>();
                nodeMap.put("id", String.valueOf(node.id()));
                
                // 安全获取名称
                if (node.containsKey("name")) {
                    nodeMap.put("name", node.get("name").asString());
                } else {
                    nodeMap.put("name", "未命名");
                }
                
                // 获取节点类型
                List<String> labels = new ArrayList<>();
                node.labels().forEach(labels::add);
                String nodeType = labels.contains("Product") ? "Product" : 
                                (labels.contains("Material") ? "Material" : labels.get(0));
                nodeMap.put("type", nodeType);
                
                // 获取描述
                if (node.containsKey("description")) {
                    nodeMap.put("description", node.get("description").asString());
                } else {
                    nodeMap.put("description", "");
                }
                
                // 其他属性
                Map<String, Object> properties = new HashMap<>(node.asMap());
                properties.remove("name");
                properties.remove("description");
                nodeMap.put("properties", properties);
                
                nodes.add(nodeMap);
            }
            
            // 处理关系
            for (Relationship rel : relList) {
                Map<String, Object> relMap = new HashMap<>();
                relMap.put("id", String.valueOf(rel.id()));
                relMap.put("source", String.valueOf(rel.startNodeId()));
                relMap.put("target", String.valueOf(rel.endNodeId()));
                relMap.put("type", rel.type());
                
                // 关系属性
                Map<String, Object> properties = new HashMap<>(rel.asMap());
                relMap.put("properties", properties);
                
                relationships.add(relMap);
            }
            
            return Map.of(
                "nodes", nodes,
                "relationships", relationships
            );
        }
        
        // 如果没有结果，返回空数据结构
        return Map.of(
            "nodes", new ArrayList<>(),
            "relationships", new ArrayList<>()
        );
    }
    
    /**
     * 处理产品链查询结果
     */
    private Map<String, Object> processProductChain(Transaction tx, String query, String productName) {
        Result result = tx.run(query, parameters("productName", productName));
        
        List<Map<String, Object>> nodes = new ArrayList<>();
        List<Map<String, Object>> relationships = new ArrayList<>();
        Set<String> processedNodeIds = new HashSet<>();
        Set<String> processedRelIds = new HashSet<>();
        
        if (result.hasNext()) {
            Record record = result.next();
            
            // 处理节点
            List<Node> nodeList = record.get("allNodes").asList(Value::asNode);
            for (Node node : nodeList) {
                String nodeId = String.valueOf(node.id());
                if (!processedNodeIds.contains(nodeId)) {
                    Map<String, Object> nodeMap = new HashMap<>();
                    nodeMap.put("id", nodeId);
                    
                    // 安全获取名称
                    if (node.containsKey("name")) {
                        nodeMap.put("name", node.get("name").asString());
                    } else {
                        nodeMap.put("name", "未命名");
                    }
                    
                    // 获取节点类型
                    List<String> labels = new ArrayList<>();
                    node.labels().forEach(labels::add);
                    String nodeType = labels.contains("Product") ? "Product" : 
                                    (labels.contains("Material") ? "Material" : labels.get(0));
                    nodeMap.put("type", nodeType);
                    
                    // 获取描述
                    if (node.containsKey("description")) {
                        nodeMap.put("description", node.get("description").asString());
                    } else {
                        nodeMap.put("description", "");
                    }
                    
                    // 其他属性
                    Map<String, Object> properties = new HashMap<>(node.asMap());
                    properties.remove("name");
                    properties.remove("description");
                    nodeMap.put("properties", properties);
                    
                    nodes.add(nodeMap);
                    processedNodeIds.add(nodeId);
                }
            }
            
            // 处理关系
            List<Relationship> relList = record.get("allRelationships").asList(Value::asRelationship);
            for (Relationship rel : relList) {
                String relId = String.valueOf(rel.id());
                if (!processedRelIds.contains(relId)) {
                    Map<String, Object> relMap = new HashMap<>();
                    relMap.put("id", relId);
                    relMap.put("source", String.valueOf(rel.startNodeId()));
                    relMap.put("target", String.valueOf(rel.endNodeId()));
                    relMap.put("type", rel.type());
                    
                    // 关系属性
                    Map<String, Object> properties = new HashMap<>(rel.asMap());
                    relMap.put("properties", properties);
                    
                    relationships.add(relMap);
                    processedRelIds.add(relId);
                }
            }
        }
        
        return Map.of(
            "nodes", nodes,
            "relationships", relationships
        );
    }
} 